package org.fastiot.data

import grails.databinding.BindUsing
import org.fastiot.protocol.Data

/**
 * 根据应用场景，重组数据间的逻辑关系，实现数据的实时/分时聚合。
 */
class DataSet {

    static enum AggregateScene {
        RealTime(0), TimeSharing(1), FullTime(9)
        final int value

        private AggregateScene(int value) { this.value = value }

        static AggregateScene byValue(int val) {
            values().find { it.value == val } ?:
                    { throw new IllegalArgumentException("DataSet\$AggregateScene ${val} not found") }()
        }
    }

    static enum TimeSharingCycle {
        Hourly(0), Daily(1), Weekly(2), Monthly(3), Custom(9)
        final int value

        private TimeSharingCycle(int value) { this.value = value }

        static TimeSharingCycle byValue(int val) {
            values().find { it.value == val } ?:
                    { throw new IllegalArgumentException("DataSet\$TimeSharingCycle ${val} not found") }()
        }
    }

    static enum StorageForm {
        ByTime(0), ByField(1)
        final int value

        private StorageForm(int value) { this.value = value }

        static StorageForm byValue(int val) {
            values().find { it.value == val } ?:
                    { throw new IllegalArgumentException("DataSet\$StorageForm ${val} not found") }()
        }
    }

    /**
     * 唯一标识
     * Uniquely identifies
     */
    String code

    /**
     * 简要名称
     * Summary Description
     */
    String name

    /**
     * 聚合场景
     * Aggregate scenes
     */
    @BindUsing({ obj, source ->
        AggregateScene.byValue(Integer.parseInt(source["scene"] as String))
    })
    AggregateScene scene

    /**
     * 分时周期
     */
    @BindUsing({ obj, source ->
        TimeSharingCycle.byValue(Integer.parseInt(source["cycle"] as String))
    })
    TimeSharingCycle cycle

    /**
     * （分时）存储形式
     * Storage form
     */
    @BindUsing({ obj, source ->
        StorageForm.byValue(Integer.parseInt(source["form"] as String))
    })
    StorageForm form = StorageForm.ByTime

    /**
     * 简要说明
     * Summary Description
     */
    String remark

    Date dateCreated
    Date lastUpdated

    static constraints = {
        code(blank: false, unique: true)
        name(blank: false, unique: true)
        scene(nullable: false, inList: DataSet.AggregateScene.values().toList())
        cycle(nullable: true, inList: DataSet.TimeSharingCycle.values().toList(), validator: DataSet.ValidateTimeSharingRules)
        form(nullable: true, inList: DataSet.StorageForm.values().toList(), validator: DataSet.ValidateTimeSharingRules)
        remark(nullable: true)
        dateCreated()
        lastUpdated()
    }

    static ValidateTimeSharingRules = { val, obj, errors ->
        if (obj.scene != AggregateScene.RealTime && val == null) {
            errors.rejectValue("scene", "Cycle and form must be set when 'TimeSharing' is selected")
        } else if (obj.scene != AggregateScene.RealTime && val == null) {
            errors.rejectValue("scene", "Cycle and form must be NULL when 'TimeSharing' is not selected")
        }
    }

    static mapping = {
        remark type: "text"
    }
}
